//: C24:Selfrtti.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 1999
// Copyright notice in Copyright.txt
// Your own RTTI system
#include "../purge.h"
#include <iostream>
#include <vector>
using namespace std;

class Security
{
protected:
    static const int baseID = 1000;
public:
    virtual int dynamic_type(int id) {
        if (id == baseID) return 1;
        return 0;
    }
};

class Stock : public Security
{
protected:
    static const int typeID = baseID + 1;
public:
    int dynamic_type(int id) {
        if (id == typeID) return 1;
        return Security::dynamic_type(id);
    }
    static Stock* dynacast(Security* s) {
        if (s->dynamic_type(typeID))
            return (Stock*)s;
        return 0;
    }
};

class Bond : public Security
{
protected:
    static const int typeID = baseID + 2 ;
public:
    int dynamic_type(int id) {
        if (id == typeID) return 1;
        return Security::dynamic_type(id);
    }
    static Bond* dynacast(Security* s) {
        if (s->dynamic_type(typeID))
            return (Bond*)s;
        return 0;
    }
};

class Commodity : public Security
{
protected:
    static const int typeID = baseID + 3;
public:
    int dynamic_type(int id) {
        if (id == typeID) return 1;
        return Security::dynamic_type(id);
    }
    static Commodity* dynacast(Security* s) {
        if (s->dynamic_type(typeID))
            return (Commodity*)s;
        return 0;
    }
    void special() {
        cout << "special Commodity function\n";
    }
};

class Metal : public Commodity
{
protected:
    static const int typeID = baseID + 4;
public:
    int dynamic_type(int id) {
        if (id == typeID) return 1;
        return Commodity::dynamic_type(id);
    }
    static Metal* dynacast(Security* s) {
        if (s->dynamic_type(typeID))
            return (Metal*)s;
        return 0;
    }
};

int main()
{
    vector<Security*> portfolio;
    portfolio.push_back(new Metal);
    portfolio.push_back(new Commodity);
    portfolio.push_back(new Bond);
    portfolio.push_back(new Stock);
    vector<Security*>::iterator it =
        portfolio.begin();
    while (it != portfolio.end()) {
        Commodity* cm = Commodity::dynacast(*it);
        if (cm) cm->special();
        else cout << "not a Commodity" << endl;
        it++;
    }
    cout << "cast from intermediate pointer:\n";
    Security* sp = new Metal;
    Commodity* cp = Commodity::dynacast(sp);
    if (cp) cout << "it's a Commodity\n";
    Metal* mp = Metal::dynacast(sp);
    if (mp) cout << "it's a Metal too!\n";
    purge(portfolio);
} ///:~
